import form from './form'
import { hasOwn, isArray, isFunction, isString } from '@web-utils/core'
import { patch } from '@/util'
import { flowRejectDialog, flowSendDialog, flowWithdrawDialog } from '@/components/flowable'
import { getFlowContext, getFlowLogs, startProcess } from '@/api/admin/workitem'
import { mapState } from 'vuex'

/**
 * 初始化流程上下文信息
 * @param businessKey
 * @param taskId
 * @param flowContext
 * @param defaultFlowContext
 * @returns {Promise<void>}
 */
async function initFlowContext({ businessKey, taskId, flowContext, defaultFlowContext }) {
  const { data } = await getFlowContext(businessKey, taskId)
  if (data.hasNext) {
    data.nextNodes.forEach(item => {
      item.handlers.forEach(value => {
        value.name = `${value.name}(${value.deptName})`
      })
    })
  }
  patch(flowContext, data.data)
}

/**
 * 初始化流转日志
 * @param businessKey
 * @param flowContext
 * @param defaultFlowContext
 * @returns {Promise<void>}
 */
async function initFlowLogs({ businessKey, flowContext, defaultFlowContext }) {
  const { data: res } = await getFlowLogs(businessKey)
  if (res.data) {
    flowContext.logs = res.data
  } else {
    flowContext.logs = defaultFlowContext.logs
  }
}

/**
 * 发送
 * @param isFinish
 * @param flowContext
 * @param businessKey
 * @param variables
 * @returns {Promise<unknown>}
 */
async function flowSend({ isFinish, flowContext, businessKey, variables }) {
  return new Promise((resolve, reject) => {
    const listeners = {
      success: async (key, entity) => {
        resolve({ key, entity })
      },
      close: () => {
        reject(Error('取消发送'))
      }
    }
    flowSendDialog({ listeners, props: { isFinish, flowContext, businessKey, variables } })
  })
}

async function flowReject({ visible, flowContext, businessKey, variables }) {
  return new Promise((resolve, reject) => {
    const listeners = {
      success: async (key, entity) => {
        resolve({ key, entity })
      },
      close: () => {
        reject(Error('取消发送'))
      }
    }
    flowRejectDialog({ listeners, props: { visible, flowContext, businessKey, variables } })
  })
}

async function flowWithdraw({ visible, flowContext, businessKey, variables }) {
  return new Promise((resolve, reject) => {
    const listeners = {
      success: async (key, entity) => {
        resolve({ key, entity })
      },
      close: () => {
        reject(Error('取消发送'))
      }
    }
    flowWithdrawDialog({ listeners, props: { visible, flowContext, businessKey, variables } })
  })
}

export default {
  mixins: [form],
  flowForm: true,
  initHooks: ['initFlow'],
  props: {
    taskId: String
  },
  provide() {
    return {
      flowContext: this.flowContext,
      formEntity: this.entity
    }
  },
  data() {
    return {
      /**
       * 流程上下文
       */
      flowContext: {
        /**
         * 流程日志列表
         */
        logs: [],
        taskId: '',
        canWithdraw: false,
        canReject: false,
        isStartNode: false,
        hasNext: false,
        loopCharacteristics: false,
        id: '',
        name: '',
        nextNodes: [],
        variables: {},
        handlers: [],
        /**
         * 启用按钮
         */
        enabledButtons: [],
        /**
         * 禁用按钮
         */
        disabledButtons: [],
        /**
         * 启用字段
         */
        enabledFields: [],
        /**
         * 禁用字段
         */
        hideFields: []
      }
    }
  },
  computed: {
    ...mapState('user', {
      userName: state => state.sysUser.name,
      userId: state => state.sysUser.userId
    }),
    hasNext() {
      return this.flowContext.hasNext
    },
    /**
     * 文档类型
     * @returns {string}
     */
    docType() {
      return this.$options.docType
    },
    /**
     * 可用按钮
     * @returns {[]}
     */
    availableButtons() {
      return this.flowContext.enabledButtons
    },
    /**
     * 不可用按钮
     * @returns {[]}
     */
    disableButtons() {
      return this.flowContext.disabledButtons
    },
    /**
     * 可操作字段
     * @returns {[]}
     */
    enabledFields() {
      return this.flowContext.enabledFields
    },
    /**
     * 不可操作字段
     * @returns {[]}
     */
    disabledFields() {
      return this.flowContext.enabledFields
    },
    /**
     * 环节编码
     * @returns {string}
     */
    nodeCode() {
      return this.flowContext.id
    },
    /**
     * 业务 key
     * @returns {string}
     */
    businessKey() {
      return `${this.docType}:${this.entity.id}`
    },
    /**
     * 是不是草稿状态
     * @returns {boolean}
     */
    isDraft() {
      return Number(this.entity.status) === 0
    },
    /**
     * 是不是完成状态
     * @returns {boolean}
     */
    isFinish() {
      return Number(this.entity.status) === 2
    },
    /**
     * 是不是在处理中
     * @returns {boolean}
     */
    isProcessing() {
      return Number(this.entity.status) === 1
    },
    /**
     * 是不是创建人
     * @returns {boolean}
     */
    isCreator() {
      return (this.entity.createId || this.entity.creator) === this.userId
    },
    /**
     * 能否显示撤回按钮
     * @returns {boolean}
     */
    canWithdraw() {
      return this.isDisabled && this.isCreator && this.isProcessing && this.flowContext.logs.length === 1
    },
    /**
     * 能否显示编辑按钮
     * @returns {boolean}
     */
    canEdit() {
      return this.isDisabled && this.isCreator && this.isDraft
    },
    /**
     * 能否显示提交按钮
     * @returns {*|boolean}
     */
    canSubmit() {
      return this.isEnabled && this.isDraft && this.validateId()
    }
  },
  watch: {
    taskId: 'initFlow'
  },
  beforeCreate() {
    if (!this.$options.docType) {
      console.warn('请在 options 里添加 docType: xxx')
    }
  },
  methods: {
    /**
     * 表单初始化完成后
     */
    async initFormState() {
      if (!hasOwn(this.entity, 'status')) {
        this.entity.status = 0
        this.$set(this.entity, 'status', 0)
      }

      await this.invalidate()

      await this.$nextTick()
      await this.setFormSaved(true)

      if (this.isCreator && this.isDraft) {
        this.setFormDisabled(false)
      } else {
        this.setFormDisabled(true)
      }

      console.log('afterInitForm')
      await this.afterInitForm()

      this.setFormLoaded(true)
    },
    /**
     * 初始化流程
     * @returns {Promise<void>}
     */
    async initFlow() {
      try {
        if (this.validateId()) {
          const { flowContext: defaultFlowContext } = this.$options.data.call(this)
          const { flowContext, businessKey, taskId } = this
          await initFlowContext({ businessKey, taskId, flowContext, defaultFlowContext })
          await initFlowLogs({ businessKey, flowContext, defaultFlowContext })
        }
      } catch (e) {
        console.error(e)
      }
    },
    /**
     * 提交审批
     * @param viewId {string?} 要更新组件的 id,可不传
     * @param beforeSend {Function?} 发送之前的回调
     * @param success {Function?} 发送成功后的回调
     * @param variables {Record?} 环节变量
     * @param isFinish {boolean?} 是不是完成
     * @param entity {Record?}
     * @return {Promise<void>}
     */
    async submitAudit({ viewId, beforeSend, success, variables, isFinish, entity = this.entity } = {}) {
      try {
        await this.validate()
        await this.update(entity)
        this.setFormSaved(true)
        if (isFunction(beforeSend)) {
          await beforeSend()
        }
        const props = {
          businessKey: this.businessKey,
          visible: true,
          isFinish,
          flowContext: this.flowContext,
          variables
        }
        const res = await flowSend(props)
        if (isFunction(success)) {
          await success(res)
        }

        await this.initForm()
        this.updateRelativeView(viewId)
        const { taskId, ...query } = this.$route.query
        await this.$router.push({ path: this.$route.path, query })
        // this.$closeTab()
      } catch (e) {
        console.error(e)
      }
    },
    /**
     * 撤回审批
     * @param viewId {string?} 要更新组件的 id,可不传
     * @param success {Function} 发送成功后的回调
     * @param variables {Record?}
     * @returns {Promise<void>}
     */
    async withdrawAudit({ viewId, success, variables } = {}) {
      try {
        await this.validate()
        await this.update(this.entity)
        this.setFormSaved(true)
        const props = { businessKey: this.businessKey, visible: true, flowContext: this.flowContext, variables }
        await flowWithdraw(props)
        if (isFunction(success)) {
          await success()
        }
        this.notifyAndUpdateView('撤回成功!', viewId)
        const { taskId, ...query } = this.$route.query
        await this.$router.push({ path: this.$route.path, query })
        await this.initForm()
      } catch (e) {
        console.error(e)
      }
    },
    /**
     *
     * @param viewId 要更新组件的 id,可不传
     * @param success 发送成功后的回调
     * @param variables {Record?}
     * @return {Promise<void>}
     */
    async reject({ viewId, success, variables } = {}) {
      try {
        await this.validate()
        await this.update(this.entity)
        this.setFormSaved(true)
        const props = { businessKey: this.businessKey, visible: true, flowContext: this.flowContext, variables }
        await flowReject(props)
        if (isFunction(success)) {
          await success()
        }
        this.notifyAndUpdateView('退回成功!', viewId)
        const { taskId, ...query } = this.$route.query
        await this.$router.push({ path: this.$route.path, query })
        await this.initForm()
      } catch (e) {
        console.error(e)
      }
    },
    async saveAndStart({ viewId, title, variables }) {
      await this.persist({
        viewId,
        afterSave: async entity => {
          await startProcess({
            processDefinitionKey: this.docType,
            businessKey: `${this.docType}:${entity.id}`,
            formId: entity.id,
            title,
            variables
          })
        }
      })
    },
    /**
     * 清除表单验证结果
     * @returns {Promise<void>}
     */
    async invalidate() {
      await this.$nextTick()
      this.$refs.form?.clearValidate()
    },
    /**
     * 验证表单
     * @returns {Promise<void>}
     */
    async validate() {
      let valid
      if (!this.$refs.form) {
        throw Error('请在表单上添加 ref="form"')
      }
      try {
        valid = await this.$refs.form.validate()
      } catch (e) {
        throw Error('表单验证不通过!')
      }
      if (valid === undefined) {
        throw Error('请在表单上添加 :model="entity"')
      }
    },
    /**
     * 判断是否有指定按钮
     * @param buttons
     * @param any
     * @returns {*}
     */
    hasBtn(buttons, any = true) {
      if (isString(buttons)) {
        if (this.isExcludeBtn(buttons)) {
          return false
        }
        return this.availableButtons.includes(buttons)
      } else if (isArray(buttons)) {
        if (any) {
          return buttons.some(value => !this.isExcludeBtn(value) && this.availableButtons.includes(value))
        }
        return buttons.every(value => !this.isExcludeBtn(value) && this.availableButtons.includes(value))
      } else {
        return false
      }
    },
    isExcludeBtn(button) {
      return this.disableButtons.includes(button)
    }
  }
}
